package com.project.springboot.utils;

import com.project.springboot.config.MinioConfig;
import io.minio.*;
import io.minio.http.Method;
import jakarta.annotation.Resource;
import lombok.Cleanup;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * description: minio工具类
 * @author 朱正磊
 * @date 2024-10-14 14:57:16
 */
@Slf4j
@Component
public class MinioUtil {

    @Resource
    private MinioClient minioClient;

    @Resource
    private MinioConfig minioConfig;

    /**
     * description: 判断bucket是否存在，不存在则创建
     * @author 朱正磊
     * @date 2024-10-14 15:07:37
     * @param bucketName 存储bucket名称
     * @return 存在返回true，不存在返回false
     */
    public Boolean existBucket(String bucketName) {
        boolean exists;
        try {
            exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
            if (!exists) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
                exists = true;
            }
        } catch (Exception e) {
            log.error("异常信息：", e);
            exists = false;
        }
        return exists;
    }

    /**
     * description: 创建存储bucket
     * @author 朱正磊
     * @date 2024-10-14 15:08:19
     * @param bucketName 存储bucket名称
     * @return 创建成功返回true，创建失败返回false
     */
    public Boolean makeBucket(String bucketName) {
        try {
            minioClient.makeBucket(MakeBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("异常信息：", e);
            return false;
        }
        return true;
    }

    /**
     * description: 删除存储bucket
     * @author 朱正磊
     * @date 2024-10-14 15:09:01
     * @param bucketName 存储bucket名称
     * @return 删除成功返回true，删除失败返回false
     */
    public Boolean removeBucket(String bucketName) {
        try {
            minioClient.removeBucket(RemoveBucketArgs.builder()
                    .bucket(bucketName)
                    .build());
        } catch (Exception e) {
            log.error("异常信息：", e);
            return false;
        }
        return true;
    }

    /**
     * description: 获取上传临时签名
     * @author 朱正磊
     * @date 2024-10-14 15:10:40
     * @param fileName 文件名称
     * @param time 时间
     * @return 返回临时签名
     */
    public Map<String, String> getPolicy(String fileName, ZonedDateTime time) {
        PostPolicy postPolicy = new PostPolicy(minioConfig.getBucketName(), time);
        postPolicy.addEqualsCondition("key", fileName);
        try {
            Map<String, String> map = minioClient.getPresignedPostFormData(postPolicy);
            HashMap<String, String> map1 = new HashMap<>();
            map.forEach((k, v) -> map1.put(k.replaceAll("-", ""), v));
            map1.put("host", minioConfig.getUrl() + "/" + minioConfig.getBucketName());
            return map1;
        } catch (Exception e) {
            log.error("异常信息：", e);
        }
        return null;
    }

    /**
     * description: 获取上传文件的url
     * @author 朱正磊
     * @date 2024-10-14 15:14:07
     * @param fileName 文件名（包含后缀名）
     * @param method 方法
     * @param time 时间
     * @param timeUnit 时间单位
     * @return 返回上传文件的url
     */
    public String getPolicyUrl(String fileName, Method method, int time, TimeUnit timeUnit) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(method)
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .expiry(time, timeUnit).build());
        } catch (Exception e) {
            log.error("异常信息：", e);
        }
        return null;
    }

    /**
     * description: 使用putObject上传一个文件到存储桶中。
     * @author 朱正磊
     * @date 2024-10-14 15:15:00
     * @param file 文件
     * @param fileName 文件名（包含后缀名）
     */
    public void upload(MultipartFile file, String fileName) {
        try {
            @Cleanup
            InputStream inputStream = file.getInputStream();
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
        } catch (Exception e) {
            log.error("异常信息：", e);
        }
    }

    /**
     * description: 根据filename获取文件访问地址
     * @author 朱正磊
     * @date 2024-10-14 15:15:45
     * @param fileName 文件名（包含后缀名）
     * @param time 时间
     * @param timeUnit 时间单位
     * @return 返回文件访问地址
     */
    public String getUrl(String fileName, int time, TimeUnit timeUnit) {
        String url = null;
        try {
            url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .expiry(time, timeUnit).build());
        } catch (Exception e) {
            log.error("异常信息：", e);
        }
        return url;
    }

    /**
     * description: 下载文件
     * @author 朱正磊
     * @date 2024-10-14 15:15:51
     * @param fileName 文件名（包含后缀名）
     * @return 返回响应对象
     */
    public ResponseEntity<byte[]> download(String fileName) {
        ResponseEntity<byte[]> responseEntity = null;
        InputStream in = null;
        ByteArrayOutputStream out = null;
        try {
            in = minioClient.getObject(GetObjectArgs.builder().bucket(minioConfig.getBucketName()).object(fileName).build());
            out = new ByteArrayOutputStream();
            IOUtils.copy(in, out);
            //封装返回值
            byte[] bytes = out.toByteArray();
            HttpHeaders headers = new HttpHeaders();
            try {
                headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            } catch (Exception e) {
                log.error("异常信息：", e);
            }
            headers.setContentLength(bytes.length);
            headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
            headers.setAccessControlExposeHeaders(Collections.singletonList("*"));
            responseEntity = new ResponseEntity<>(bytes, headers, HttpStatus.OK);
        } catch (Exception e) {
            log.error("异常信息：", e);
        } finally {
            try {
                if (in != null) {
                    try {
                        in.close();
                    } catch (Exception e) {
                        log.error("异常信息：", e);
                    }
                }
                if (out != null) {
                    out.close();
                }
            } catch (Exception e) {
                log.error("异常信息：", e);
            }
        }
        return responseEntity;
    }

    /**
     * description: 获取文件url地址
     * @author 朱正磊
     * @date 2024-10-14 15:15:58
     * @param fileName 文件名（包含后缀名）
     * @return 返回文件url地址
     */
    public String getFileUrl(String fileName) {
        try {
            return minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
                    .method(Method.GET)
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .build()
            );
        } catch (Exception e) {
            log.error("异常信息：", e);
        }
        return null;
    }

}
